package cn.itcast.dewu.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.itcast.dewu.dto.Result;
import cn.itcast.dewu.pojo.Goods;
import cn.itcast.dewu.pojo.GoodsCart;
import cn.itcast.dewu.pojo.VoucherOrder;
import cn.itcast.dewu.service.GoodsCartService;
import cn.itcast.dewu.service.GoodsService;
import cn.itcast.dewu.utils.RabbitConfirmCallbackUtil;
import cn.itcast.dewu.utils.RedisIdWork;
import cn.itcast.dewu.utils.UserHolder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.itcast.dewu.pojo.GoodsOrder;
import cn.itcast.dewu.service.GoodsOrderService;
import cn.itcast.dewu.mapper.GoodsOrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static cn.itcast.dewu.utils.RedisConstants.GOODS_STOCK_KEY;
import static cn.itcast.dewu.utils.RedisConstants.VOUCHER_ORDER_KEY;

/**
 * @author Administrator
 * @description 针对表【tb_goods_order】的数据库操作Service实现
 * @createDate 2022-04-29 14:06:30
 */
@Service
@Slf4j
public class GoodsOrderServiceImpl extends ServiceImpl<GoodsOrderMapper, GoodsOrder>
        implements GoodsOrderService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisIdWork idWork;
    @Autowired
    private GoodsService goodsService;

    /*
     * 购买普通的商品*/
    @Override
    public Result buyGoods(Long goodsId) {
        //查看库存
        String goodsStock = stringRedisTemplate.opsForValue().get("goods:special:stock:"+ goodsId);
        if (StrUtil.isEmpty(goodsStock)) {
            return Result.fail("抱歉.当前商品的库存不足^_^");
        }
        Integer stock = Integer.valueOf(goodsStock);
        if (stock <= 0) {
            return Result.fail("抱歉.当前商品的库存不足^_^");
        }

        long orderId = idWork.nextID("byGoods" + goodsId);

        //获取到当前登录用户
        Long userId = UserHolder.getUser().getId();
        GoodsOrder goodsOrder = new GoodsOrder();
        goodsOrder.setGoodsId(goodsId);
        goodsOrder.setUserId(userId);
        goodsOrder.setId(orderId);
        //先减库存
        boolean update = goodsService.update().setSql("stock = stock - 1").update();
        if (update) {
            boolean save = save(goodsOrder);

            if (save) {
                boolean falg = goodsService.update().setSql("sold = sold+1").update();
                if (falg)
                    //去redis中减少库存
                    stringRedisTemplate.opsForValue().increment(GOODS_STOCK_KEY + goodsId, -1);
            }
        }
        return Result.ok(orderId);
    }

    //执行lua脚本
    private static final DefaultRedisScript<Long> LUA_VOUCHER_SCRIPT;

    static {
        LUA_VOUCHER_SCRIPT = new DefaultRedisScript<>(); //获取lua脚本
        Resource resource = new ClassPathResource("goodsSckill.lua"); //获取文件的路径
        LUA_VOUCHER_SCRIPT.setLocation(resource);
        LUA_VOUCHER_SCRIPT.setResultType(long.class); //设置文件的返回类型
    }

    /*
     * 购买特价商品
     * 需求 有库存限制 并且每人每件只能买一次
     * 执行lua脚本来保证原子的一致性 发送到rabbitmq 来保证异步的去更新收据库 效率提升
     * */
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public Result buySpecialGoods(Long goodsId) {
        //获取到当前登录用户
        Long userId = UserHolder.getUser().getId();
        //生成订单id
        long orderID = idWork.nextID("byGoods" + goodsId);
        //执行lua脚本
        Long result = stringRedisTemplate.execute(
                LUA_VOUCHER_SCRIPT,
                Collections.emptyList(),//这里无键,因为脚本中的键是由value值获取到的
                goodsId.toString(), userId.toString()
        );
        int value = result.intValue();
        if (value != 0) {
            return Result.fail(value == 1 ? "库存不足^_^" : "特价商品,不允许重复下单^_^");
        }
        GoodsOrder goodsOrder = new GoodsOrder();
        goodsOrder.setId(orderID).setUserId(userId).setGoodsId(goodsId);
        //发送到rabbitmq中
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString(true));
        correlationData.getFuture().addCallback(
                result2 -> {
                    if (result2.isAck()) {
                        log.info("消息发送成功,消息id为:{}", correlationData.getId());
                    } else {
                        log.error("消息发送到交换机失败,消息的id为:{},发送失败的原因为:{}"
                                , correlationData.getId(), result2.getReason());
                        //重新发送消息
                        rabbitTemplate.convertAndSend("specialgoods.orderexchange",
                                "specialgoods.order", goodsOrder, correlationData);
                    }
                },
                ex -> {
                    log.error("消息发送异常,消息的id为:{},发送失败的原因为:{}"
                            , correlationData.getId(), ex.getMessage());
                    //重新发送消息
                    rabbitTemplate.convertAndSend("specialgoods.orderexchange",
                            "specialgoods.order", goodsOrder, correlationData);
                }
        );
        //发送消息
        rabbitTemplate.convertAndSend("specialgoods.orderexchange",
                "specialgoods.order", goodsOrder, correlationData);

        return Result.ok(orderID);


    }

    @Autowired
    private GoodsCartService goodsCartService;

    /*
     * 加入购物车
     * */
    @Override
    public Result saveGoodToCart(Long goodsId) {
        //获取当前用户
        Long userId = UserHolder.getUser().getId();
        Goods goods = goodsService.getById(goodsId);
        GoodsCart goodsCart = new GoodsCart();
        long goodsCartId = idWork.nextID("goods:cart:" + goodsId);
        goodsCart.setId(goodsCartId).setGoodsId(goodsId).setUserId(userId);

        //加入购物车
        boolean save = goodsCartService.save(goodsCart);
        if (save)
            stringRedisTemplate.opsForValue().set("goods:to:cart:" + userId + goodsId,
                    JSONUtil.toJsonStr(goods));

        return Result.ok("加入购物车成功");
    }


    /*
     * 查看当前用户购物车
     * */
    @Override
    public Result lookCart() {
        //获取当前登录用户
        Long userId = UserHolder.getUser().getId();
        //从redis中查询购物车
        Set<String> keys = stringRedisTemplate.keys("goods:to:cart:" + userId + "*");
        List<String> goodsList = stringRedisTemplate.opsForValue().multiGet(keys);
        if (goodsList.isEmpty()) {
            return Result.ok(Collections.emptyList());
        }

        List<Goods> collect = goodsList.stream().
                map(goods -> JSONUtil.toBean(goods, Goods.class)).collect(Collectors.toList());
        return Result.ok(collect);
    }

    @Override
    public Result removeCart(Map<String, Long> map) {
        if (map.isEmpty()) {
            return Result.fail("你尚未选中商品^^");
        }
        //获取到当前登录的id
        Long userId = UserHolder.getUser().getId();
        List<Long> goodsIds = map.values().stream().collect(Collectors.toList());
        System.out.println(goodsIds);
        Set<String> redisKeys = goodsIds.stream()
                .map(goodsId -> "goods:to:cart:" + userId + goodsId)
                .collect(Collectors.toSet());
        /*
        * 先删除数据库*/
        List<GoodsCart> goodsCarts = goodsCartService.query().in("goods_id", goodsIds)
                .eq("user_id",userId).list();
        List<Long> collect = goodsCarts.stream().map(GoodsCart::getId).collect(Collectors.toList());
        boolean falg = goodsCartService.removeByIds(collect);
        if (falg)
        stringRedisTemplate.delete(redisKeys);
        return Result.ok();
    }
}




